﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

using MyLibrary.ThreeLayer.DataAccess.Enum;
using MyLibrary.ThreeLayer.DataAccess.Attributes;

namespace MyLibrary.ThreeLayer.DataAccess.MetaData
{
    public abstract class MappingField
    {
        public string ColumnName;
        public string DisplayName;
        public bool HasColumnAttribute = false;
        public bool HasNoMapAttribute = false;
        public bool IsPrimaryKey;
        public PrimaryKeyType KeyGenerateType;
        public Type KeyGenerator;
        public string Name;
        public Type Owner = null;
        public Type RefEntityType = null;
        public Type Type;

        protected MappingField()
        {
        }

        public abstract object GetValue(object entity);
        public abstract void SetValue(object entity, object value);
    }

    public class PropertyField : MappingField
    {
        protected PropertyInfo _PropertyInfo;

        public PropertyField(PropertyInfo property)
        {
            base.Name = property.Name;
            this._PropertyInfo = property;
            //泛型
            if (property.PropertyType.IsGenericType)
            {
                Type[] genericArguments = property.PropertyType.GetGenericArguments();
                base.Type = genericArguments[0];
            }
            else
                base.Type = property.PropertyType;

            //处理自定义属性
            //处理列自定义属性
            object[] customerAttributes = property.GetCustomAttributes(typeof(ColumnAttribute), true);
            if (customerAttributes.Length > 0)
            {
                base.HasColumnAttribute = true;
                ColumnAttribute attributes = (ColumnAttribute)customerAttributes[0];
                base.ColumnName = attributes._Name;

                //如果自定义属性没有指定列名,将属性名做为列名进行赋值
                if (String.IsNullOrEmpty(base.ColumnName))
                    base.Owner = property.Name;
                //设置所属的类型
                if (attributes._Owner != null)
                    base.Owner = attributes._Owner;
                else
                    base.Owner = property.DeclaringType;
            }
            else
            {
                base.ColumnName = property.Name;
                base.Owner = property.DeclaringType;
            }
            
            //非映射列
            if (property.GetCustomAttributes(typeof(NoMappingAttribute), true).Length > 0)
                base.HasNoMapAttribute = true;

            //主键属性
            customerAttributes = property.GetCustomAttributes(typeof(PrimaryKeyAttribute), true);
            if (customerAttributes.Length > 0)
            {
                PrimaryKeyAttribute pAttribute = customerAttributes[0] as PrimaryKeyAttribute;
                base.IsPrimaryKey = true;
                base.KeyGenerateType = pAttribute._PrimaryKeyType;
                base.KeyGenerator = pAttribute._KeyGeneratorType;
            }

            //引用类型属性
            customerAttributes = property.GetCustomAttributes(typeof(RefAttribute), true);
            if (customerAttributes.Length > 0)
            {
                RefAttribute rAttribut = customerAttributes[0] as RefAttribute;
                base.RefEntityType = rAttribut._RefType;
            }
        }

        public override object GetValue(object entity)
        {
            if (this._PropertyInfo.CanRead)
            {
                object obj = this._PropertyInfo.GetValue(entity, null);
                if (obj == null)
                    return DBNull.Value;
                return obj;
            }
            return null;
        }

        public override void SetValue(object entity, object value)
        {
            if (this._PropertyInfo.CanWrite)
            {
                if (value == null)
                    this._PropertyInfo.SetValue(entity, null, null);
                else
                {
                    try
                    {
                        this._PropertyInfo.SetValue(entity, Convert.ChangeType(value, base.Type), null);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("无法将指定的值绑定到字段上,不能从" + value.GetType().ToString() + "转化为" + base.Type + "|--" + ex.Message, ex);
                    }
                }

            }
        }
    }
}
